package com.mxchip.livestar.original;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;

import com.mxchip.livestar.utils.MyLog;

import java.util.Arrays;

/**
 * Created by Administrator on 2016/12/28.
 * 音频推送
 */

public class AudioPublisher {

    private static final String TAG = "AudioPublisher";
    private AudioRecord mic;
    private volatile AudioCallback audioCallback;
    private volatile boolean aloop = false;
    private Thread aworker;
    private int SAMPLERATE = 16000;//采样频率
    private static final int CHANNEL = AudioFormat.CHANNEL_IN_MONO;
    private static final int AUDIOFORMAT = AudioFormat.ENCODING_PCM_16BIT;//16位采样精度

    int bufferSizeInBytes = AudioRecord.getMinBufferSize(SAMPLERATE,
            CHANNEL, AUDIOFORMAT);
    private int PUSH_AUDIO_LENGTH = bufferSizeInBytes;

    public AudioPublisher() {
        MyLog.logD(MyLog.AUDIO_SEND_MODEL, "AudioPublisher::AudioPublisher: bufferSizeInBytes:" + bufferSizeInBytes);
    }

    public AudioPublisher(int samplerate) {
        this.SAMPLERATE = samplerate;
        this.PUSH_AUDIO_LENGTH = 1920;

    }

    public interface AudioCallback {
        void onGetPcmFrame(byte[] data, int size);

        void AudioOPenFail();
    }

    public void setAudioCallback(AudioCallback cb) {
        audioCallback = cb;
    }

    //开始推送音频
    public void startPublishAudio() {
        aworker = new Thread(new Runnable() {
            @Override
            public void run() {
                android.os.Process
                        .setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
                startAudio();
            }
        });
        aloop = true;
        aworker.start();
    }

    private int notConsumed;
    private int consumed;
    private int totalLength = 640;
    private int dataSize = 0;
    private int blockSize = 640;
    private int next = 0;
    private byte[][] dataBuffer = new byte[2][640];

    //开启音频
    private void startAudio() {
        if (mic != null) {
            return;
        }
        try {
            mic = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLERATE, CHANNEL, AUDIOFORMAT, PUSH_AUDIO_LENGTH * 2);

            mic.startRecording();
            MyLog.logD(MyLog.AUDIO_SEND_MODEL, "AudioPublisher::" + "startAudio: " + mic.getRecordingState());
            while (mic.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
                // Wait until we can start recording...
            }
            byte pcmBuffer[] = new byte[PUSH_AUDIO_LENGTH];
            while (aloop && !Thread.interrupted()) {
                int ret = mic.read(pcmBuffer, 0, pcmBuffer.length);
                MyLog.logD(MyLog.AUDIO_SEND_MODEL, "startAudio:" + " pcmBuffer:" + pcmBuffer.length + " ret:" + ret);
                if (ret == AudioRecord.ERROR || ret == AudioRecord.ERROR_INVALID_OPERATION || ret == AudioRecord.ERROR_BAD_VALUE) {
                    stopMuc();
                    startAudio();
                    return;
                }

                notConsumed = ret;
                if (audioCallback != null) {
                    if (blockSize > notConsumed) {
                        System.arraycopy(pcmBuffer, 0, dataBuffer[next], dataSize, notConsumed);
                        dataSize += notConsumed;
                        blockSize -= notConsumed;
                    } else {
                        System.arraycopy(pcmBuffer, 0, dataBuffer[next], dataSize, blockSize);
                        if (audioCallback != null) {
                            byte[] dst = new byte[640];
                            System.arraycopy(dataBuffer[next], 0, dst, 0, dataBuffer[next].length);
                            audioCallback.onGetPcmFrame(dst, dst.length);
                        }
                        next = (next + 1) % 2;
                        dataSize = 0;

                        notConsumed = notConsumed - blockSize;
                        consumed += blockSize;
                        while (notConsumed > dataBuffer[next].length) {
                            System.arraycopy(pcmBuffer, consumed, dataBuffer[next], dataSize, dataBuffer[next].length);
                            if (audioCallback != null) {
                                byte[] dst = new byte[640];
                                System.arraycopy(dataBuffer[next], 0, dst, 0, dataBuffer[next].length);
                                audioCallback.onGetPcmFrame(dst, dst.length);
                            }
                            notConsumed = notConsumed - dataBuffer[next].length;
                            next = (next + 1) % 2;
                            dataSize = 0;
                            consumed += dataBuffer[next].length;
                        }
                        System.arraycopy(pcmBuffer, pcmBuffer.length - notConsumed, dataBuffer[next], dataSize, notConsumed);
                        dataSize = notConsumed;
                        blockSize = totalLength - dataSize;
                        consumed = 0;
                    }

                }
//                if (audioCallback != null) {
//                    audioCallback.onGetPcmFrame(pcmBuffer, ret);
//                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            stopMuc();
            if (audioCallback != null) {
                audioCallback.AudioOPenFail(/*"音频设备被占用\n请重新启动设备"*/);
            }
        }
    }

    //停止推送音频
    public void stopPublishAudio() {

        aloop = false;
        for (byte[] bytes : dataBuffer) {
            Arrays.fill(bytes, (byte) 0);
        }
        audioCallback = null;
        stopMuc();
        if (aworker != null) {
            aworker = null;
        }


    }

    private void stopMuc() {
        if (mic != null) {
            mic.setRecordPositionUpdateListener(null);
            try {
                mic.stop();

            } catch (IllegalStateException e) {
                e.printStackTrace();
            } finally {
                if (mic != null) {
                    mic.release();
                    mic = null;
                }
            }
        }

    }


}
